package com.yanqu.road.server.gameplayer.module.mail;

import com.yanqu.road.entity.enums.eItemId;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eMailType;
import com.yanqu.road.entity.log.LogDeleteMail;
import com.yanqu.road.entity.player.UserMail;
import com.yanqu.road.logic.bussiness.player.UserMailBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.MailPb;
import com.yanqu.road.pb.mail.MailProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.banquet.BanquetModule;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.gameplayer.module.player.DecorationModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.mail.ServerMailMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 邮件、消息模块
 */
public class MailModule extends GeneralModule {

	private Map<String, UserMail> mailMap;

	private Map<String, UserMail> backendMailMap; // 后台角色邮件查询用

	public MailModule(GamePlayer player) {
		super(player);
	}

	@Override
	public boolean loadData() {
		mailMap = new ConcurrentHashMap<>();
		backendMailMap = new ConcurrentHashMap<>();
		Map<String, UserMail> tempMailMap = UserMailBussiness.getUserMailMap(player.getUserId());

		for (UserMail data : tempMailMap.values()) {
			if (!MailManager.isMailExpired(data)) {
                mailMap.put(data.getMailUid(), data);
			}
		}

		for (UserMail data : tempMailMap.values()) { // 显示系统邮件、日常邮件、后台邮件 或者 有附件但是过期的
			if ((data.getMailType() != eMailType.SYSTEM.getValue()
					&& data.getMailType() != eMailType.DAILY.getValue()
					&& data.getMailType() != eMailType.MARKETING.getValue())
                || (StringUtils.isNullOrEmpty(data.getAnnexes())
					&& System.currentTimeMillis() - data.getSendTime().getTime() > GameConfig.MAIL_NO_ANNEXES_EXPIRED_DAY * DateHelper.DAY_MILLIONS)) {
				continue;
			}
			backendMailMap.put(data.getMailUid(), data);
		}

		return true;
	}

	@Override
	public boolean afterLoadData() {
		ServerMailMgr.playerGetServerMail(player);
		return true;
	}

	@Override
	public boolean saveData() {
		if(null != mailMap) {
			synchronized (mailMap) {
				for (UserMail data : mailMap.values()) {
					if (data.isInsertOption()) {
						UserMailBussiness.addUserMail(data);
					} else if (data.isUpdateOption()) {
						UserMailBussiness.updateUserMail(data);
					}
				}
			}
		}
		return true;
	}

	@Override
	public void afterLogin() {
		syncMail(getShowMailList(), true);
	}

	@Override
	public void loginSendMsg() {

	}

	private void syncMail(UserMail userMail){
		if(null != userMail){
			List<UserMail> syncList = new ArrayList<>();
			syncList.add(userMail);
			syncMail(syncList, false);
		}
	}

	public void syncMail(List<UserMail> userMailList, boolean isLogin){
		MailProto.MailListMsg.Builder listMsg = MailPb.parseMailListMsg(userMailList);
		if(isLogin){
			player.sendPacket(Protocol.U_MAIL_LIST, listMsg);
		}else {
			player.sendPacket(Protocol.U_MAIL_SYNC, listMsg);
		}
	}

	public void syncAllMail() {
		syncMail(getShowMailList(), false);
	}

	public List<UserMail> getShowMailList() {
		List<UserMail> showMailList = new ArrayList<>();
		int mailNum = 0;
		List<UserMail> hasReadAndReceive = new ArrayList<>();
		List<UserMail> goldTokenMailList = new ArrayList<>();
		for (UserMail userMail : mailMap.values()) {
			//包含代币的邮件
			Property reward = PropertyHelper.parseStringToProperty(userMail.getAnnexes());
			if(null != reward && reward.getGoods().containsKey(eItemId.GOLD_TOKEN.getValue())){
				goldTokenMailList.add(userMail);
			}

			if (MailManager.isMailExpired(userMail)) {//邮件过期
				continue;
			}

			if (!userMail.isRead() || (userMail.isRead() && !StringUtils.isNullOrEmpty(userMail.getAnnexes()) && !userMail.isGetReward())) {
				// 未读 或者 (已读并且有附件未领取)
				showMailList.add(userMail);
			} else {
				hasReadAndReceive.add(userMail);
			}

		}

		// 未读未领取 超过数量限制
		if (showMailList.size() >= GameConfig.MAIL_MAX_COUNT) {
			showMailList.sort(Comparator.comparing(UserMail::getSendTime));
			return showMailList.subList(showMailList.size() - GameConfig.MAIL_MAX_COUNT, showMailList.size());
		}

		// 全部邮件 超过数量限制
		if (showMailList.size() + hasReadAndReceive.size() > GameConfig.MAIL_MAX_COUNT) {
			int addCount = GameConfig.MAIL_MAX_COUNT - showMailList.size();
			hasReadAndReceive.sort(Comparator.comparing(UserMail::getSendTime));
			showMailList.addAll(hasReadAndReceive.subList(hasReadAndReceive.size() - addCount, hasReadAndReceive.size()));
			return showMailList;
		}

		// 全部邮件 未超过数量限制
		showMailList.addAll(hasReadAndReceive);

		//加上代币邮件
		showMailList.addAll(goldTokenMailList);
		return showMailList;

	}

	public boolean addUserMail(UserMail userMail) {
		mailMap.put(userMail.getMailUid(), userMail);
		backendMailMap.put(userMail.getMailUid(), userMail);
		syncMail(userMail);
		return true;
	}

	/**
	 * 获取邮件奖励(附件)
	 */
	public int getMailReward(String mailUid) {
		UserMail mail = getUserMail(mailUid);
		if (null == mail) {
			return GameErrorCode.E_MAIL_NOT_EXIST;
		}
		if (mail.getSendTime().compareTo(new Date()) > 0) {
			return GameErrorCode.E_MAIL_GET_TIME_NO_ARRIVE;
		}
		if (mail.isGetReward()) {
			return GameErrorCode.E_MAIL_GET_ALREADY;
		}
		if (MailManager.isMailExpired(mail)) {
			return GameErrorCode.E_MAIL_EXPIRED;
		}
		openUserMail(mail);
		return 0;
	}

	public UserMail getUserMail(String mailUid) {
		if (null == mailMap) {
			return null;
		}
		return mailMap.get(mailUid);
	}

	public String openUserMail(UserMail userMail) {
		//邮件防止add道具时报错 导致报错前的物品重复领取
		userMail.setRead(true);
		userMail.setReadTime(new Date());
		userMail.setGetReward(true);
		CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
		Property property = PropertyHelper.parseStringToProperty(userMail.getAnnexes());
		currencyModule.addCurrency(property, eLogMoneyType.Mail, eLogMoneyType.MailOpen, userMail.getSendTime());
		if(null != property) {
			property.getGoods().forEach((k, v) -> {
				if (GoodsMgr.isDecorationGoods(k)) {
					player.getModule(DecorationModule.class).setServerIds(k, userMail.getActivityId(), userMail.getServerList());
				}
			});
		}
		player.getModule(BanquetModule.class).getCrossBanquetInvitationReward(userMail.getAnnexes(), userMail.getServerList());
		return userMail.getMailUid();
	}

	public int readUserMail(String mailUid) {
		UserMail userMail = getUserMail(mailUid);
		if (null == userMail) {
			return GameErrorCode.E_MAIL_NOT_EXIST;
		}
		userMail.setRead(true);
		userMail.setReadTime(new Date());
		return 0;
	}

	public int deleteMail(String mailUid) {
		synchronized (mailMap) {
			UserMail userMail = getUserMail(mailUid);
			if (null == userMail) {
				return GameErrorCode.E_MAIL_NOT_EXIST;
			}
			Property rewardProperty = PropertyHelper.parseStringToProperty(userMail.getAnnexes());
			if(null != rewardProperty && !userMail.isGetReward()){
				return GameErrorCode.E_MAIL_NO_GET;
			}
			// 邮件删除日志
			AutoLogMgr.add(new LogDeleteMail(userMail.getMailUid(), userMail.getMailType(), userMail.getTitle(), userMail.getContent(), userMail.getAnnexes(), userMail.getSendTime(), userMail.getSendUserId(), userMail.getSendNickName(), userMail.getReceiveUserId(), userMail.isRead(), userMail.getReadTime(), userMail.isGetReward(), userMail.isDelete()));
			mailMap.remove(userMail.getMailUid());
			UserMailBussiness.deleteUserMail(userMail.getMailUid());
			//删除过期邮件
            for (UserMail tempMail : mailMap.values()) {
                if (tempMail.getSendTime().compareTo(new Date()) <= 0) {
                    if (MailManager.isMailExpired(tempMail)) {
						// 邮件删除日志
						AutoLogMgr.add(new LogDeleteMail(tempMail.getMailUid(), tempMail.getMailType(), tempMail.getTitle(), tempMail.getContent(), tempMail.getAnnexes(), tempMail.getSendTime(), tempMail.getSendUserId(), tempMail.getSendNickName(), tempMail.getReceiveUserId(), tempMail.isRead(), tempMail.getReadTime(), tempMail.isGetReward(), tempMail.isDelete()));
                        mailMap.remove(tempMail.getMailUid());
                        UserMailBussiness.deleteUserMail(tempMail.getMailUid());
                    }
                }
            }
		}

		synchronized (backendMailMap) {
			backendMailMap.remove(mailUid);
		}
		return 0;
	}

	public int deleteAllMailByType(boolean checkMailType, List<Integer> mailType) {
		int ret;
		List<String> uidList = new ArrayList<>();
		synchronized (mailMap) {
			for (UserMail userMail : mailMap.values()) {
				if (userMail.getSendTime().compareTo(new Date()) <= 0) {
					Property rewardProperty = PropertyHelper.parseStringToProperty(userMail.getAnnexes());
					if (((userMail.isGetReward() || rewardProperty == null || rewardProperty.getGoods().size() == 0) && userMail.isRead()) ||
                        MailManager.isMailExpired(userMail)) {
						if (!checkMailType || mailType.contains(userMail.getMailType())) {
							// 邮件删除日志
							AutoLogMgr.add(new LogDeleteMail(userMail.getMailUid(), userMail.getMailType(), userMail.getTitle(), userMail.getContent(), userMail.getAnnexes(), userMail.getSendTime(), userMail.getSendUserId(), userMail.getSendNickName(), userMail.getReceiveUserId(), userMail.isRead(), userMail.getReadTime(), userMail.isGetReward(), userMail.isDelete()));
							mailMap.remove(userMail.getMailUid());
							uidList.add(userMail.getMailUid());
						}
					}
				}
			}
		}

		synchronized (backendMailMap) {
			for (String mailUid : uidList) {
				backendMailMap.remove(mailUid);
			}
		}

		if (uidList.size() == 0) {
			ret = GameErrorCode.E_MAIL_NO_CAN_DELETE;//没有邮件可删除
		} else {
			UserMailBussiness.deleteUserMailList(uidList);
			ret = 0;
		}
		syncMail(getShowMailList(), true);
		return ret;
	}

	public List<String> getAllMailReward() {
		List<String> dataList = new ArrayList<>();
		for (UserMail mail : mailMap.values()) {
			if (!mail.isGetReward() && mail.getSendTime().compareTo(new Date()) <= 0 && !MailManager.isMailExpired(mail)) {
				dataList.add(openUserMail(mail));
			}
		}
		return dataList;
	}

	/**
	 * 一键领取日常邮件奖励
	 */
	public String getAllDailyMailReward() {
		List<UserMail> toSyncMailList = new ArrayList<>();
		Property allReward = new Property();
		synchronized (mailMap) {
			for (UserMail mail : mailMap.values()) {
				if (!mail.isGetReward() && mail.getSendTime().compareTo(new Date()) <= 0 && !MailManager.isMailExpired(mail)) {
					// 只领取每日的
					if (mail.getMailType() == eMailType.DAILY.getValue()) {
						openUserMail(mail);
						if (!StringUtils.isNullOrEmpty(mail.getAnnexes())) {
							allReward.addProperty(PropertyHelper.parseStringToProperty(mail.getAnnexes()));
						}
						toSyncMailList.add(mail);
					}
				}
			}
		}
		syncMail(toSyncMailList, false);
		return PropertyHelper.parsePropertyToString(allReward);
	}

	/**
	 * 后台删除邮件
	 *
	 * @param mailUid mailUid
	 * @return
	 */
	public boolean backendDeleteMail(String mailUid) {
		synchronized (backendMailMap) {
			UserMail userMail = getBackendUserMail(mailUid);
			if (userMail == null) {
				return false;
			}

			// 邮件删除日志
			AutoLogMgr.add(new LogDeleteMail(userMail.getMailUid(), userMail.getMailType(), userMail.getTitle(), userMail.getContent(),
					userMail.getAnnexes(), userMail.getSendTime(), userMail.getSendUserId(), userMail.getSendNickName(), userMail.getReceiveUserId(),
					userMail.isRead(), userMail.getReadTime(), userMail.isGetReward(), userMail.isDelete()));
			backendMailMap.remove(userMail.getMailUid());
			UserMailBussiness.deleteUserMail(userMail.getMailUid());
		}

		synchronized (mailMap) { // 正常展示的邮件中如果包含也需要去除
			mailMap.remove(mailUid);
			syncMail(getShowMailList(), true);
		}

		return true;
	}

	public Map<String, UserMail> getBackendMailMap() {
		if (backendMailMap == null) {
			backendMailMap = new ConcurrentHashMap<>();
		}
		return backendMailMap;
	}

	public UserMail getBackendUserMail(String mailUid) {
		if (null == backendMailMap) {
			return null;
		}
		return backendMailMap.get(mailUid);
	}
}
